package com.xzc.one.common.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.*;

/**
 * 乱七八糟的工具
 *
 * @author xiongzhicong
 * @create 2019-10-31 13:34
 **/
public class ToolUtil {

    public static class IsUtil {

        // 判断字符串是否为空或长度为0
        public static boolean isEmpty(String str) {
            return (str == null || str.length() == 0);
        }

        public static boolean isNotEmpty(String str) {
            return !isEmpty(str);
        }

        // 判断一个对象是否为空
        public static boolean isNull(Object obj) {
            if (obj == null) return true;
            if (obj instanceof Map) {
                Map map = (Map) obj;
                return (map.size() == 0);
            } else if (obj instanceof List) {
                List list = (List) obj;
                return (list.size() == 0 || list.get(0) == null);
            }
            return false;
        }

        public static boolean isNotNull(Object obj) {
            return !isNull(obj);
        }

        public static boolean isNullOrEmpty(Object obj) {
            return isNull(obj) || isEmpty(obj + "");
        }

        public static boolean isNotNullOrEmpty(Object obj) {
            return !isNull(obj) && !isEmpty(obj + "");
        }
    }

    public static class BigUtil {

        public static String add(Object... objects) {
            if (objects.length == 0) return "0";
            BigDecimal str = BigDecimal.ZERO;
            for (Object o : objects) {
                if (IsUtil.isNull(o)) o = 0;
                BigDecimal big = new BigDecimal(o + "");
                str = str.add(big);
            }
            return str.toString();
        }

        public static String subtract(Object a, Object b) {
            if (IsUtil.isNull(a)) a = 0;
            if (IsUtil.isNull(b)) b = 0;
            BigDecimal big1 = new BigDecimal(a + "");
            BigDecimal big2 = new BigDecimal(b + "");
            return big1.subtract(big2).toString();
        }


        public static String multiply(Object... objects) {
            if (objects.length == 0) return "0";
            BigDecimal str = BigDecimal.ONE;
            for (Object o : objects) {
                if (IsUtil.isNull(o)) o = 0;
                BigDecimal big = new BigDecimal(o + "");
                str = str.multiply(big);
            }
            return str.toString();
        }

        /**
         * 除法
         *
         * @param a a
         * @param b b
         * @param n 保留n位小数，n可省略
         * @return 字符串
         */
        public static String divide(Object a, Object b, int... n) {
            if (IsUtil.isNull(a) || IsUtil.isNull(b)) return "0";
            BigDecimal big1 = new BigDecimal(a + "");
            BigDecimal big2 = new BigDecimal(b + "");
            int len = 4;
            if (n != null && n.length > 0)
                len = n[0];
            return big1.divide(big2, len, BigDecimal.ROUND_HALF_UP).toString();
        }

        public static void main(String[] args) {
            System.out.println(multiply(5.5555, 6.888888, 84.45));
            System.out.println(add(5.5555, 6.888888, 84.45));
        }

        /**
         * 保留n位小数
         *
         * @param big b
         * @param n   保留n位小数，n可省略
         * @return 字符串
         */
        public static String bigDouble(String big, int... n) {
            if (IsUtil.isNull(big)) big = "0";
            BigDecimal bd = new BigDecimal(big);
            int len = 2;
            if (n != null && n.length > 0) {
                len = n[0];
            }
            //直接舍去
            int roundDown = BigDecimal.ROUND_DOWN;
            //四舍五入
            int roundHalfUp = BigDecimal.ROUND_HALF_UP;
            return bd.setScale(len, roundHalfUp).toString();
        }

        /**
         * 返回 小数 或整数 （有小数的返回小数，没小数的返回整数）
         *
         * @param big b
         * @param n   保留n位小数，n可省略
         * @return 字符串
         */
        public static String bigXz(String big, int... n) {
            String str = bigDouble(big, n);
            BigDecimal bg = new BigDecimal(str);
            double v = bg.doubleValue();
            if (Math.round(v) - v == 0)
                return (long) v + "";
            return str;
        }
    }

    public static class RandomUtil {
        private static final String NUMBERS = "0123456789";
        private static final String LETTERSL = "abcdefghijklmnopqrstuvwxyz";
        private static final String LETTERSU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private static final String NUMBER_LETTERS = NUMBERS + LETTERSL + LETTERSU;
        private static final String[] FONTNAMES = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"};   //字体数组

        public static int randomInt(int max) {
            return new Random().nextInt(max);
        }

        public static String randomStr(int length) {
            StringBuilder str = new StringBuilder("");
            for (int i = 0; i < length; i++) {
                str.append(NUMBER_LETTERS.charAt(randomInt(NUMBER_LETTERS.length())));
            }
            return str.toString();
        }

        public static Color randomColor() {
            return new Color(randomInt(256), randomInt(256), randomInt(256));
        }

        public static Font randomFont() {
            String fontName = FONTNAMES[randomInt(FONTNAMES.length)];//获取随机的字体
            int style = randomInt(4);            //随机获取字体的样式，0是无样式，1是加粗，2是斜体，3是加粗加斜体
            int size = randomInt(10) + 25;              //随机获取字体的大小
            return new Font(fontName, style, size);   //返回一个随机的字体
        }

        public static String randomTime() {
            return LocalDateTime.of(randomInt(3000), randomInt(12) + 1, randomInt(31) + 1,
                    randomInt(24), randomInt(60), randomInt(60)).toString();
        }

        public static void main(String[] args) {
            System.out.println(randomTime());
        }

    }

    public static class ValidUtil {

        private static final String numAll = "^([+-]?)\\d*\\.?\\d+$";//数字
        private static final String numInt = "^-?[1-9]\\d*$";//整数
        private static final String numIntZ = "^[1-9]\\d*$";//正整数
        private static final String numIntF = "^-[1-9]\\d*$";//负整数
        private static final String numIntZO = "^[1-9]\\d*|0$";//非负整数（正整数 + 0）
        private static final String numIntFO = "^-[1-9]\\d*|0$";//非正整数（负整数 + 0）
        private static final String numFloat = "^([+-]?)\\d*\\.\\d+$";//浮点数
        private static final String numFloatZ = "^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*$";//正浮点数
        private static final String numFloatF = "^-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*)$";//负浮点数
        private static final String numFloatZO = "^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*|0?.0+|0$";//非负浮点数（正浮点数 + 0）
        private static final String numFloatFO = "^(-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*))|0?.0+|0$";//非正浮点数（负浮点数 + 0）

        private static final String mobile = "^1(3|4|5|6|7|8|9)[0-9]{9}$";
        private static final String telAndMobile = "^\\+[0-9]{2}\\-(13|15|18|17|16)[0-9]{9}$";
        private static final String percentage = "^(100|[1-9]?\\d(\\.\\d\\d?\\d?)?)|0$";
        private static final String email = "^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$";//邮件
        private static final String color = "^[a-fA-F0-9]{6}$";//颜色
        private static final String url = "^http[s]?=\\/\\/([\\w-]+\\.)+[\\w-]+([\\w-./?%&=]*)?$";//url
        private static final String chinese = "^[\\u4E00-\\u9FA5\\uF900-\\uFA2D]+$";//仅中文
        private static final String ascii = "^[\\x00-\\xFF]+$";//仅ACSII字符
        private static final String zipCode = "^\\d{6}$";//邮编
        private static final String ip4 = "^(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)$";//ip地址
        private static final String notEmpty = "^\\S+$";//非空
        private static final String picture = "(.*)\\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$";//图片
        private static final String rar = "(.*)\\.(rar|zip|7zip|tgz)$";//压缩文件
        private static final String date = "^\\d{4}(\\-|\\/|\\.)\\d{1,2}\\1\\d{1,2}$";//日期
        private static final String qq = "^[1-9]*[1-9][0-9]*$";//QQ号码
        private static final String tel = "^(([0\\+]\\d{2,3}-)?(0\\d{2,3})-)?(\\d{7,8})(-(\\d{1,}))?$";//电话号码(包括验证国内区号;国际区号;分机号)
        private static final String username = "^\\w+$";//用户注册 匹配由数字、26个英文字母或者下划线
        private static final String letter = "^[A-Za-z]+$";//字母
        private static final String letterAndSpace = "^[A-Za-z ]+$";
        private static final String letter_u = "^[A-Z]+$";//大写字母
        private static final String letter_l = "^[a-z]+$";//小写字母
        private static final String idcard = "^[1-9]([0-9]{14}|[0-9]{17})$";//身份证
        private static final String isCarVin = "^[1234567890WERTYUPASDFGHJKLZXCVBNM]{13}[0-9]{4}$";//判断车辆Vin码

        public static boolean isMobile(String input) {
            return matches(mobile, input);
        }

        public static boolean isTelAndMobile(String input) {
            return matches(telAndMobile, input);
        }

        public static boolean isNumAll(String input) {
            return matches(numAll, input);
        }

        public static boolean isNumInt(String input) {
            return matches(numInt, input);
        }


        public static boolean isNumFloat(String input) {
            return matches(numFloat, input);
        }

        public static boolean isEmail(String input) {
            return matches(email, input);
        }

        public static boolean isColor(String input) {
            return matches(color, input);
        }

        public static boolean isUrl(String input) {
            return matches(url, input);
        }

        public static boolean isChinese(String input) {
            return matches(chinese, input);
        }

        public static boolean isAscii(String input) {
            return matches(ascii, input);
        }

        public static boolean isZipCode(String input) {
            return matches(zipCode, input);
        }

        public static boolean isIP4(String input) {
            return matches(ip4, input);
        }

        public static boolean isNotEmpty(String input) {
            return matches(notEmpty, input);
        }

        public static boolean isPicture(String input) {
            return matches(picture, input);
        }

        public static boolean isRar(String input) {
            return matches(rar, input);
        }

        public static boolean isDate(String input) {
            return matches(date, input);
        }

        public static boolean isQQ(String input) {
            return matches(qq, input);
        }

        public static boolean isTel(String input) {
            return matches(tel, input);
        }

        public static boolean isUserName(String input) {
            return matches(username, input);
        }

        public static boolean isLetter(String input) {
            return matches(letter, input);
        }

        public static boolean isLetterAndSpace(String input) {
            return matches(letterAndSpace, input);
        }

        public static boolean isLowLetter(String input) {
            return matches(letter_l, input);
        }

        public static boolean isUpperLetter(String input) {
            return matches(letter_u, input);
        }

        public static boolean isIDCard(String input) {
            return matches(idcard, input);
        }

        public static boolean isCarVin(String carVin) {
            return matches(isCarVin, carVin);
        }

        public static boolean matches(String regex, String input) {
            if (IsUtil.isEmpty(input)) return false;
            return input.matches(regex);
        }

        public static void main(String[] args) {
            System.out.println(isMobile("15979177296"));
            System.out.println(isLetter("tai  wan"));
        }
    }

    public static class StringUtil {

        public static final String NO_PREFIX = "NO";

        public static int getNum(String prefix, String str) {
            if (str == null || str.trim().equals("") || prefix.length() > str.trim().length()) return 0;
            String num = str.substring(prefix.length());
            return Integer.parseInt(num);
        }

        public static String getStrNum(String prefix, int num) {
            return prefix + String.format("%010d", num);
        }

        public static String getXh(String string) {
            return String.format("%s****%s", string.substring(0, 3), string.substring(string.length() - 4));
        }

        public static void main(String[] args) {
            String str = getStrNum(NO_PREFIX, 1000000000);
            System.out.println(str);
            System.out.println(getNum(NO_PREFIX, str));
        }
    }

    public static class LocationUtil {
        private static final double EARTH_RADIUS = 6378.137;//地球平均半径

        //把经纬度转为度（°）
        private static double rad(double d) {
            return d * Math.PI / 180.0;
        }

        /**
         * 通过经纬度获取距离(单位：米)
         *
         * @param lat1
         * @param lng1
         * @param lat2
         * @param lng2
         * @return 距离
         */
        public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
            double radLat1 = rad(lat1);
            double radLat2 = rad(lat2);
            double a = radLat1 - radLat2;
            double b = rad(lng1) - rad(lng2);
            double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                    + Math.cos(radLat1) * Math.cos(radLat2)
                    * Math.pow(Math.sin(b / 2), 2)));
            s = s * EARTH_RADIUS;
            s = Math.round(s * 10000d) / 10000d;
            s = s * 1000;
            return s;
        }

        public static Integer getDistanceInt(BigDecimal lat1, BigDecimal lng1, BigDecimal lat2,
                                             BigDecimal lng2) {
            double d = getDistance(lat1.doubleValue(), lng1.doubleValue(), lat2.doubleValue(), lng2.doubleValue());
            return (int) d;
        }

        public static String mMileShow(BigDecimal dis) {
            if (dis.compareTo(new BigDecimal(1000)) < 0) {
                return dis.intValue() + "m";
            } else {
                return dis.divide(new BigDecimal(1000), 2).intValue() + "km";
            }
        }

        public static void main(String[] args) {
            double distance = getDistance(34.2675560000, 108.9534750000,
                    34.2464320000, 108.9534750000);
            System.out.println("距离" + distance / 1000 + "公里");
        }


    }

    public static class FirstLetterUtil {
        private static int BEGIN = 45217;
        private static int END = 63486;
        // 按照声母表示，这个表是在GB2312中的出现的第一个汉字，也就是说“啊”是代表首字母a的第一个汉字。
        // i, u, v都不做声母, 自定规则跟随前面的字母
        private static char[] chartable = {'啊', '芭', '擦', '搭', '蛾', '发', '噶', '哈',
                '哈', '击', '喀', '垃', '妈', '拿', '哦', '啪', '期', '然', '撒', '塌', '塌',
                '塌', '挖', '昔', '压', '匝',};
        // 二十六个字母区间对应二十七个端点
        // GB2312码汉字区间十进制表示
        private static int[] table = new int[27];
        // 对应首字母区间表
        private static char[] initialtable = {'a', 'b', 'c', 'd', 'e', 'f', 'g',
                'h', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
                't', 't', 'w', 'x', 'y', 'z',};

        // 初始化
        static {
            for (int i = 0; i < 26; i++) {
                table[i] = gbValue(chartable[i]);// 得到GB2312码的首字母区间端点表，十进制。
            }
            table[26] = END;// 区间表结尾
        }

        /**
         * 根据一个包含汉字的字符串返回一个汉字拼音首字母的字符串 最重要的一个方法，思路如下：一个个字符读入、判断、输出
         */
        public static String getFirstLetter(String sourceStr) {
            String result = "";
            String str = sourceStr.toLowerCase();
            int StrLength = str.length();
            int i;
            try {
                for (i = 0; i < StrLength; i++) {
                    result += Char2Initial(str.charAt(i));
                }
            } catch (Exception e) {
                result = "";
            }
            return result;
        }

        /**
         * 输入字符,得到他的声母,英文字母返回对应的大写字母,其他非简体汉字返回 '0'
         */
        private static char Char2Initial(char ch) {
            // 对英文字母的处理：小写字母转换为大写，大写的直接返回
            if (ch >= 'a' && ch <= 'z') {
                return ch;
            }
            if (ch >= 'A' && ch <= 'Z') {
                return ch;
            }
            // 对非英文字母的处理：转化为首字母，然后判断是否在码表范围内，
            // 若不是，则直接返回。
            // 若是，则在码表内的进行判断。
            int gb = gbValue(ch);// 汉字转换首字母
            if ((gb < BEGIN) || (gb > END))// 在码表区间之前，直接返回
            {
                return ch;
            }
            int i;
            for (i = 0; i < 26; i++) {// 判断匹配码表区间，匹配到就break,判断区间形如“[,)”
                if ((gb >= table[i]) && (gb < table[i + 1])) {
                    break;
                }
            }
            if (gb == END) {//补上GB2312区间最右端
                i = 25;
            }
            return initialtable[i]; // 在码表区间中，返回首字母
        }

        /**
         * 取出汉字的编码 cn 汉字
         */
        private static int gbValue(char ch) {// 将一个汉字（GB2312）转换为十进制表示。
            String str = new String();
            str += ch;
            try {
                byte[] bytes = str.getBytes("GB2312");
                if (bytes.length < 2) {
                    return 0;
                }
                return (bytes[0] << 8 & 0xff00) + (bytes[1] & 0xff);
            } catch (Exception e) {
                return 0;
            }
        }

        public static void main(String[] args) {
            System.out.println(getFirstLetter("中国"));
        }
    }

    public static class UUIDMD5Util {
        /**
         * 对字符串md5加密(大写+数字)
         *
         * @param s 传入要加密的字符串
         * @return MD5加密后的字符串
         */
        public static String MD5(String s) {

            char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

            try {
                byte[] btInput = s.getBytes();
                // 获得MD5摘要算法的 MessageDigest 对象
                MessageDigest mdInst = MessageDigest.getInstance("MD5");
                // 使用指定的字节更新摘要
                mdInst.update(btInput);
                // 获得密文
                byte[] md = mdInst.digest();
                // 把密文转换成十六进制的字符串形式
                int j = md.length;
                char str[] = new char[j * 2];
                int k = 0;
                for (int i = 0; i < j; i++) {
                    byte byte0 = md[i];
                    str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                    str[k++] = hexDigits[byte0 & 0xf];
                }
                return new String(str);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public static String UUID() {
            return UUID.randomUUID().toString().replaceAll("-", "");
        }

        public static void main(String[] args) {
            System.out.println(MD5("aaa"));
        }
    }

    public static class LoadFileUtil {
        private final static String classpathStatic = "static/";
        public final static String imagePath = "upload/image/";
        public final static String filePath = "upload/file/";
        public final static String videoPath = "upload/video/";
        public final static String[] allFile = {".rar", ".doc", ".docx", ".zip",
                ".pdf", ".txt", ".swf", ".xlsx", ".gif", ".png", ".jpg", ".jpeg",
                ".bmp", ".xls", ".mp4", ".flv", ".ppt", ".avi", ".mpg", ".wmv",
                ".3gp", ".mov", ".asf", ".asx", ".vob", ".wmv9", ".rm", ".rmvb"};
        public final static String[] allowFile = {".doc", ".docx", ".pdf", ".txt", ".xls", ".xlsx", ".ppt"};
        public final static String[] allowPhoto = {".png", ".jpg", ".jpeg", ".bmp"};
        public final static String[] allowVideo = {".mp4", ".flv", ".avi", ".mpg", ".wmv", ".3gp", ".mov"};

        /**
         * 上传文件至本地
         * 在开发测试模式时，得到的地址为：{项目根目录}/target/static/upload/image/
         * 在打包成jar正式发布时，得到的地址为：{发布jar包目录}/static/upload/image/
         *
         * @param path 上传路径
         * @param file 上传文件
         * @return 路径及文件名
         */
        public static String upLoad(String path, MultipartFile file) {
            System.out.println("LoadFileUtil.upLoad");
            if (file != null && !file.isEmpty()) {
                try {
                    File root = new File(ResourceUtils.getURL("classpath:").getPath()); //获取根目录
                    File upload = new File(root.getAbsolutePath(), classpathStatic + path);//上传目录/static/upload/image/
                    if (!upload.exists()) {
                        upload.mkdirs();
                    }
                    System.out.println("path>>" + upload);
                    String fileName = getName(file);
                    System.out.println("fileName>>" + fileName);
                    File dir = new File(upload + "/" + fileName);
                    file.transferTo(dir);
                    return path + fileName;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        private static String getName(MultipartFile file) {
            String prefix = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf(".")).replace(" ", "");
            String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            return prefix + UUIDMD5Util.UUID() + suffix;
        }

        public static boolean isAllow(MultipartFile file, String[] doctype) {
            if (file != null && !file.isEmpty()) {
                String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
                System.out.println(suffix);
                for (String allow : doctype) {
                    if (allow.equalsIgnoreCase(suffix)) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    public static class CodeImgUtil {

        private static final int WIDTH = 100;
        private static final int HEIGHT = 50;
        private static final String[] fontNames = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"};   //字体数组
        private static final String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";    //验证码数组

        public static BufferedImage codeImg(String code) {
            BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
            Graphics g = image.getGraphics();
            g.fillRect(0, 0, WIDTH, WIDTH);
            g.setColor(Color.BLUE);
            drawLines(g);
            drawCodes(g, code);
            return image;
        }

        private static void drawLines(Graphics g) {
            int count = randomInt(10);
            for (int i = 0; i < count; i++) {
                int x1 = randomInt(WIDTH);
                int x2 = randomInt(WIDTH);
                int y1 = randomInt(HEIGHT);
                int y2 = randomInt(HEIGHT);
                g.setColor(randomColor());
                g.drawLine(x1, y1, x2, y2);
            }
        }

        private static void drawCodes(Graphics g, String code) {
            for (int i = 0; i < code.length(); i++) {
                g.setFont(randomFont());
                g.setColor(randomColor());
                g.drawString(String.valueOf(code.charAt(i)), i * WIDTH / code.length(), HEIGHT / 2 + randomInt(HEIGHT / 2));
            }
        }

        private static void drawCodes(Graphics g) {
            int count = 4;
            for (int i = 0; i < count; i++) {
                String text = String.valueOf(randomChar());
                g.setFont(randomFont());
                g.setColor(randomColor());
                g.drawString(text, i * WIDTH / count, HEIGHT - 5);
            }
        }

        public static String getCode(int count) {
            String code = "";
            for (int i = 0; i < count; i++) {
                code += String.valueOf(codes.charAt(randomInt(codes.length())));
            }
            return code;
        }

        private static int randomInt(int max) {
            return new Random().nextInt(max);
        }

        private static char randomChar() {
            return codes.charAt(randomInt(codes.length()));
        }

        private static Color randomColor() {
            return new Color(randomInt(256), randomInt(256), randomInt(256));
        }

        private static Font randomFont() {
            String fontName = fontNames[randomInt(fontNames.length)];//获取随机的字体
            int style = randomInt(4);            //随机获取字体的样式，0是无样式，1是加粗，2是斜体，3是加粗加斜体
            int size = randomInt(10) + 25;              //随机获取字体的大小
            return new Font(fontName, style, size);   //返回一个随机的字体
        }

    }

    public static class QrCodeUtil {

        /**
         * image流数据处理
         *
         * @param matrix
         * @return
         */
        private static BufferedImage toBufferedImage(BitMatrix matrix) {
            int width = matrix.getWidth();
            int height = matrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            return image;
        }

        public static void getQrImg(String contents, int width, int height, OutputStream outputStream) {
            Hashtable hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
                BufferedImage image = toBufferedImage(bitMatrix);
                ImageIO.write(image, "jpg", outputStream);
            } catch (WriterException | IOException e) {
                e.printStackTrace();
            }
        }

        public static String getQrCode(String contents) {
            return "data:image/png;base64,\n" + creatQrCode(contents, 200, 200);
        }

        private static String creatQrCode(String contents, int width, int height) {
            String binary = null;
            Hashtable hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
                // 1、读取文件转换为字节数组
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                BufferedImage image = toBufferedImage(bitMatrix);
                ImageIO.write(image, "png", out); //转换成png格式的IO流
                byte[] bytes = out.toByteArray();

                // 2、将字节数组转为二进制
                BASE64Encoder encoder = new BASE64Encoder();
                binary = encoder.encodeBuffer(bytes).trim();
            } catch (WriterException | IOException e) {
                e.printStackTrace();
            }
            return binary;
        }

        public static void main(String[] args) {
            String binary = getQrCode("www.baidu.com");
            System.out.println(binary);
        }
    }

    public static class ShortUrlUtil {

        /**
         * 十六进制下数字到字符的映射数组
         */
        private final static String[] HEXDIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};

        /**
         * inputString加密
         */
        public static String md5(String inputStr) {
            return encodeByMD5(inputStr);
        }

        /**
         * 对字符串进行MD5编码
         */
        private static String encodeByMD5(String originString) {
            if (originString != null) {
                try {
                    //创建具有指定算法名称的信息摘要
                    MessageDigest md5 = MessageDigest.getInstance("MD5");
                    //使用指定的字节数组对摘要进行最后更新，然后完成摘要计算
                    byte[] results = md5.digest(originString.getBytes());
                    //将得到的字节数组变成字符串返回
                    String result = byteArrayToHexString(results);
                    return result;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        /**
         * 轮换字节数组为十六进制字符串
         *
         * @param b 字节数组
         * @return 十六进制字符串
         */
        private static String byteArrayToHexString(byte[] b) {
            StringBuffer resultSb = new StringBuffer();
            for (int i = 0; i < b.length; i++) {
                resultSb.append(byteToHexString(b[i]));
            }
            return resultSb.toString();
        }

        /**
         * @param b 字节
         * @return 将一个字节转化成十六进制形式的字符串
         */
        private static String byteToHexString(byte b) {
            int n = b;
            if (n < 0) {
                n = 256 + n;
            }
            int d1 = n / 16;
            int d2 = n % 16;
            return HEXDIGITS[d1] + HEXDIGITS[d2];
        }

        public static String shortUrl(String url) {
            return shortUrls(url)[0];
        }

        private static String[] shortUrls(String url) {
            // 可以自定义生成 MD5 加密字符传前的混合 KEY
            String key = "md5";
            // 要使用生成 URL 的字符
            String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h",
                    "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
                    "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                    "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
                    "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                    "U", "V", "W", "X", "Y", "Z"
            };
            // 对传入网址进行 MD5 加密
            String hex = md5(key + url);
            String[] resUrl = new String[4];
            for (int i = 0; i < 4; i++) {
                // 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
                String sTempSubString = hex.substring(i * 8, i * 8 + 8);
                // 这里需要使用 long 型来转换，因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ，则会越界
                long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
                StringBuilder outChars = new StringBuilder();
                for (int j = 0; j < 6; j++) {
                    // 把得到的值与 0x0000003D 进行位与运算，取得字符数组 chars 索引
                    long index = 0x0000003D & lHexLong;
                    // 把取得的字符相加
                    outChars.append(chars[(int) index]);
                    // 每次循环按位右移 5 位
                    lHexLong = lHexLong >> 5;
                }
                // 把字符串存入对应索引的输出数组
                resUrl[i] = outChars.toString();
            }
            return resUrl;
        }
    }

    public static class PrintUtil {

        public static void printXing(String... str) {
            if (str.length == 0)
                System.out.println(String.format("******************************************************************"));
            else if (str.length == 1)
                System.out.println(String.format("*************************** %s ***************************", str[0]));
            else
                System.out.println(String.format("%s ******************************************** %s", str[0], str[1]));
        }

        public static void printHeng(String... str) {
            if (str == null)
                System.out.println(String.format("------------------------------------------------------------------"));
            else if (str.length == 1)
                System.out.println(String.format("-------------------------- %s ----------------------------", str[0]));
            else
                System.out.println(String.format("%s -------------------------------------------- %s", str[0], str[1]));
        }

        public static void printKeyValue(String key, String value) {
            System.out.println(String.format("%20s ================================================== %s", key, value));
        }

        public static void print(String... str) {
            String string = "";
            for (String s : str) {
                string += String.format("[ %s ]-----", s);
            }
            System.out.println(string);
        }

        public static void print(Object obj) {
            if (obj instanceof List) {
                for (int i = 0; i < ((List) obj).size(); i++) {
                    print(((List) obj).get(i));
                }
            } else if (obj instanceof Map) {
                for (Object key : ((Map) obj).keySet()) {
                    printKeyValue(key.toString(), ((Map) obj).get(key).toString());
                    if (((Map) obj).get(key) instanceof Map) {
                        print(((Map) obj).get(key));
                    }
                }
            } else {
                System.out.println(obj.toString());
            }
        }

        public static void printList(List list) {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i) instanceof List) {
                    printList((List) list.get(i));
                } else {
                    System.out.println(list.get(i).toString());
                }
            }
        }

        public static void printMap(Map<String, Object> map) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object o = entry.getValue();
                if (o instanceof Map) {
                    printMap((Map<String, Object>) o);
                } else {
                    printKeyValue(entry.getKey(), entry.getValue().toString());
                }
            }
        }
    }

    public static class GetUtil {

        public static String getStr(Object obj) {
            return IsUtil.isNotNull(obj) ? obj + "" : "";
        }

        public static Integer getInteger(Object obj) {
            return IsUtil.isNotNull(obj) ? (new BigDecimal(obj.toString().trim())).intValue() : 0;
        }

        public static BigDecimal getBig(Object obj) {
            return IsUtil.isNotNullOrEmpty(obj) && obj.toString().trim().length() != 0 ? new BigDecimal(obj.toString()) : new BigDecimal(0);
        }

        public static int getInt(Object obj) {
            return IsUtil.isNotNull(obj) ? (new BigDecimal(obj.toString().trim())).intValue() : 0;
        }

        public static long getLong(Object obj) {
            return IsUtil.isNotNullOrEmpty(obj) ? Long.parseLong(obj + "") : 0L;
        }

        public static Map getMap(Map map, String... str) {
            HashMap<String, Object> newMap = new HashMap<>();
            for (String s : str) {
                newMap.put(s, getStr(map.get(s)));
            }
            return newMap;
        }

        public static Map getMap(Map map, Map returnMap, String... str) {
            for (String s : str) {
                returnMap.put(s, getStr(map.get(s)));
            }
            return returnMap;
        }
    }
}
